package com.china.zhuoyue.map

import android.Manifest
import android.os.Build
import android.os.Environment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.amap.api.location.AMapLocation
import com.amap.api.location.AMapLocationClient
import com.amap.api.location.AMapLocationClientOption
import com.amap.api.location.AMapLocationListener
import com.china.zhuoyue.ui.AppCore
import com.china.zhuoyue.ui.ext.DQPermissionRequest
import com.china.zhuoyue.ui.ext.andPermissionX
import com.china.zhuoyue.ui.ext.toastMessageLong
import com.china.zhuoyue.ui.utils.Logger

typealias OnLocationChangedListener = (aMapLocation: AMapLocation?) -> Unit

fun FragmentActivity.getLocation(onLocationChanged: OnLocationChangedListener) {
    LocationBootstrap.startLocation(this, this, onLocationChanged)
}

fun Fragment.getLocation(onLocationChanged: OnLocationChangedListener) {
    LocationBootstrap.startLocation(this, this, onLocationChanged)
}

object LocationBootstrap : AMapLocationListener {

    private val LOCATION_CLIENT: AMapLocationClient by lazy {
        AMapLocationClient(AppCore.app).apply {
            AMapLocationClientOption().apply {
                locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
                isOnceLocation = true
                isNeedAddress = true
                isMockEnable = false
            }
            setLocationListener(this@LocationBootstrap)
            stopLocation()
        }
    }
    private var mAMapLocationLifecycleObserver: AMapLocationLifecycleObserver? = null

    fun startLocation(tag: Any, lifecycleOwner: LifecycleOwner, onLocationChanged: OnLocationChangedListener) {
        mAMapLocationLifecycleObserver = AMapLocationLifecycleObserver(onLocationChanged)
        lifecycleOwner.lifecycle.addObserver(mAMapLocationLifecycleObserver!!)
        andPermissionX(tag, DQPermissionRequest().apply {
            permission(Manifest.permission.ACCESS_COARSE_LOCATION)
            permission(Manifest.permission.ACCESS_FINE_LOCATION)
            if (isNeedStoragePermission()) {
                permission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                permission(Manifest.permission.READ_EXTERNAL_STORAGE)
            }
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                permission(Manifest.permission.READ_PHONE_STATE)
            }
            onGranted {
                LOCATION_CLIENT.startLocation()
            }
            onDenied {
                release()
                "权限被拒绝无法定位".toastMessageLong()
            }
        })
    }

    override fun onLocationChanged(aMapLocation: AMapLocation?) {
        kotlin.runCatching {
            if (aMapLocation != null && aMapLocation.errorCode == 0) {
                mAMapLocationLifecycleObserver?.onLocationChanged?.invoke(aMapLocation)
            } else {
                "获取定位失败".toastMessageLong()
                mAMapLocationLifecycleObserver?.onLocationChanged?.invoke(null)
                Logger.e("${aMapLocation?.errorCode}")
                Logger.e(aMapLocation?.errorInfo)
            }
        }
        release()
    }

    private fun stopLocation() = LOCATION_CLIENT.stopLocation()

    fun release() {
        mAMapLocationLifecycleObserver?.onDestroy()
        mAMapLocationLifecycleObserver = null
        stopLocation()
    }

    private fun isNeedStoragePermission(): Boolean {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || Environment.isExternalStorageLegacy()
    }

    class AMapLocationLifecycleObserver(
        var onLocationChanged: OnLocationChangedListener?
    ) : DefaultLifecycleObserver {
        override fun onDestroy(owner: LifecycleOwner) {
            owner.lifecycle.removeObserver(this)
            release()
            onDestroy()
        }

        fun onDestroy() {
            onLocationChanged = null
        }
    }
}

